package com.faner4cloud.yun.common.util.page;


import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.IntSupplier;
import java.util.function.Supplier;

/**
 * 分页对象
 *
 * @author ...zz
 * @version v1
 * @summary desc
 * @since 2022/8/2 4:15 PM
 */
public class Pagination<T> implements Serializable {
	private static final long serialVersionUID = 1L;
	@SuppressWarnings("rawtypes")
	private static final Pagination EMPTY = emptyResult();

	private static Pagination<?> emptyResult() {
		Pagination<?> result = new Pagination<>();
		result.setPageList(Collections.emptyList());
		return result;
	}

	/**
	 * 返回一个分页数据为空的常量
	 */
	@SuppressWarnings("unchecked")
	public static <T> Pagination<T> empty() {
		return (Pagination<T>) EMPTY;
	}

	/**
	 * 提供一个标准的方式生成分页对象，如果totolCountFunction返回值大于0，才会调用分页列表函数查询数据。
	 * </p>
	 * 用法示例：
	 *
	 * <pre>
	 * <code>
	 *  public Pagination&lt;User&gt; someMethod(int pageNo,int pageSize,....){
	 *   return  Pagination.create(pageNo,pageSize,() -> userDao.count(params),
	 *     () -> userDao.paginationList(params));
	 *  }
	 * </code>
	 * </pre>
	 *
	 * @param <T>                分页Model
	 * @param pageNo             当前页码,从1开始，如果参数值小于1，则默认为1
	 * @param pageSize           每页数据大小，如果参数值小于1，则默认为20
	 * @param totolCountFunction 查询总共多少条数据的函数，不能为null
	 * @param pageList           查询分页列表的函数，countFunction返回的数据大于0，才会调用
	 */
	public static <T> Pagination<T> create(int pageNo, int pageSize, IntSupplier totolCountFunction,
										   Supplier<List<T>> pageList) {
		// 无论如何初始化一个Pagination，如果pageNo/Size<1,则初始化为1，20
		Pagination<T> pagination = new Pagination<>(pageNo, pageSize);
		int totalCnt = totolCountFunction.getAsInt();
		// 如果总记录数为0 或者当前页码*分页已经大于总记录数，则直接返回empty
		if (totalCnt < 1 || ((pageNo - 1) * pageSize) >= totalCnt) {
			// 2020年07月31日 我们发现有的用户会用个返回的对象重新构建Pagination，这时候pageNo/pageSize就会变成0
			// 就会报错，因此将返回值Pagination.empty()调整为每次new个带pageNo,pageSize的对象
			pagination.setPageList(Collections.emptyList());
			return pagination;
		}
		pagination.setTotalCount(totalCnt);
		pagination.setPageList(Optional.of(pageList.get()).orElse(Collections.emptyList()));
		return pagination;
	}

	/**
	 * 实体对象列表
	 */
	private List<T> pageList;
	/**
	 * 每页记录数，如果pageSize<=0，则默认为20.
	 */
	private int pageSize;
	/**
	 * 当前页号，如果pageNo<=0，则默认为1
	 */
	private int pageNo;
	/**
	 * 总记录数
	 */
	private int totalCount = 0;

	public Pagination() {
		super();
	}

	/**
	 * @param pageNo   页码，从1开始，如果小于1，则默认为1
	 * @param pageSize 分页大小，如果小于1，则默认为20
	 */
	public Pagination(int pageNo, int pageSize) {
		if (pageNo < 1) {
			pageNo = 1;
		}
		if (pageSize < 1) {
			pageSize = 20;
		}
		this.pageNo = pageNo;
		this.pageSize = pageSize;
	}

	public List<T> getPageList() {
		return pageList;
	}

	public void setPageList(List<T> pageList) {
		this.pageList = pageList;
	}

	/**
	 * 每页记录数，如果pageSize<=0，则默认为20.
	 */
	public int getPageSize() {
		return pageSize;
	}

	/**
	 * 每页记录数，如果pageSize<=0，则默认为20.
	 *
	 * @param pageSize
	 */
	public void setPageSize(int pageSize) {
		if (pageSize <= 0) {
			pageSize = 20;
		}
		this.pageSize = pageSize;
	}

	/**
	 * 当前页号，如果pageNo<=0，则默认为1
	 */
	public int getPageNo() {
		return pageNo;
	}

	/**
	 * 当前页号，如果pageNo<=0，则默认为1
	 *
	 * @param pageNo
	 */
	public void setPageNo(int pageNo) {
		if (pageNo <= 0) {
			pageNo = 1;
		}
		this.pageNo = pageNo;
	}

	/**
	 * 总记录数
	 */
	public int getTotalCount() {
		return totalCount;
	}

	/**
	 * 总记录数
	 *
	 * @param totalCount
	 */
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}

	/**
	 * 返回总页数
	 */
	public int getTotalPage() {
		if (getTotalCount() == 0) {
			return 1;
		} else {
			if (getTotalCount() % getPageSize() == 0) {
				return getTotalCount() / getPageSize();
			} else {
				return getTotalCount() / getPageSize() + 1;
			}
		}
	}

	/**
	 * 分页起始行
	 */
	public int getRowOffset() {
		// pageNo 小于0已判断，此处不用判断了
		return (this.pageNo - 1) * this.pageSize;
	}

	/**
	 * 返回下一页页码
	 *
	 * @return
	 */
	public int getNextPage() {
		if (isLastPage()) {
			return getTotalPage();
		} else {
			return getPageNo() + 1;
		}
	}

	/**
	 * 返回上一页页码
	 *
	 * @return
	 */
	public int getPrePage() {
		if (isFirstPage()) {
			return 1;
		} else {
			return getPageNo() - 1;
		}
	}

	/**
	 * 是否是最后一页
	 */
	public boolean isLastPage() {
		if (getTotalPage() <= 0) {
			return true;
		} else {
			return getPageNo() >= getTotalPage();
		}
	}

	/**
	 * 是否是第一页
	 */
	public boolean isFirstPage() {
		return getPageNo() <= 1;
	}
}
